//
// Created by LiuYou on 2021/8/11.
//

#include <cstdio>
#include <cstdlib>
#include <pthread.h>
#include <cerrno>
#include <sys/syslog.h>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include "Channel.hpp"
#include "../include/Types.hpp"
#include "../include/Protocol.hpp"
#include "Server.hpp"
#include "MediaLib.hpp"
#include "Channel.hpp"
#include "ChannelList.hpp"


struct ThreadChannelEntry {
    ChannelId channelId;
    pthread_t tid;
};


ThreadChannelEntry threadChannelEntry[CHANNEL_NUM];
static int tidNextPos = 0;


static void*
threadChannelSender(void* ptr) {
    MsgChannel* msgChannelBuf;
    void* pVoid = malloc(MSG_CHANNEL_MAX);
    msgChannelBuf = static_cast<MsgChannel*>(pVoid);
    if (msgChannelBuf == nullptr) {
        syslog( LOG_ERR, "malloc(): %s", strerror(errno));
        exit( 1 );
    }
//    int dataSize = NetRadio::MAX_DATA;

    MediaLibEntry* mediaLibEntry = static_cast<MediaLibEntry*>(ptr);
    msgChannelBuf->channelId = mediaLibEntry->channelId;
    while (true) {
//        int len = readChannelList( mediaLibEntry->channelId,
//                                   msgChannelBuf->data,
//                                   MAX_DATA);
        int len = readChannelList( mediaLibEntry->channelId,
                                   msgChannelBuf->data,
                                   128 * 1024 / 8 );
        if (sendto( socketFd, msgChannelBuf, len + sizeof( ChannelId ), 0,
                    (sockaddr*) &senderAddress, sizeof( senderAddress )) < 0) {
//            syslog( LOG_ERR, "threadChannelSender(%s):sendto(): %s", (char*) (mediaLibEntry->channelId),
//                    strerror(errno));
            syslog( LOG_ERR, "threadChannelSender(%d):sendto(): %s", mediaLibEntry->channelId,
                    strerror(errno));
            exit( 1 );
        } else {
            syslog( LOG_DEBUG, "threadChannelSender(%s):sendto(): succeed.", (char*) (mediaLibEntry->channelId));
        }

        sched_yield();
    }

    pthread_exit( nullptr );

}

int
threadChannelCreate(MediaLibEntry* ptrMediaLibEntry) {
    int err = pthread_create( &threadChannelEntry[tidNextPos].tid, nullptr,
                              threadChannelSender, ptrMediaLibEntry );
    if (err) {
        syslog( LOG_WARNING, "pthread_create(): %s", strerror( err ));
        return -err;
    }
    threadChannelEntry[tidNextPos].channelId = ptrMediaLibEntry->channelId;
    ++tidNextPos;

    return 0;
}

int
threadChannelDestroy(MediaLibEntry* ptrMediaLibEntry) {
    for (int i = 0; i < CHANNEL_NUM; ++i) {
        if (threadChannelEntry[i].channelId == ptrMediaLibEntry->channelId) {
            if (pthread_cancel( threadChannelEntry[i].tid ) < 0) {
                syslog( LOG_ERR, "pthread_cancel(): the thread of channel %d", ptrMediaLibEntry->channelId );
                return -ESRCH;
            }
        }

        pthread_join( threadChannelEntry[i].tid, nullptr );
        threadChannelEntry[i].channelId = -1;
        return 0;
    }

}

int
threadChannelDestroyAll() {
    for (int i = 0; i < CHANNEL_NUM; ++i) {
        if (threadChannelEntry[i].channelId > 0) {
            if (pthread_cancel( threadChannelEntry[i].tid ) < 0) {
                syslog( LOG_ERR, "pthread_cancel(): the thread of channel %d", threadChannelEntry[i].tid );
                return -ESRCH;
            }
            pthread_join( threadChannelEntry[i].tid, nullptr );
            threadChannelEntry[i].tid = -1;
        }
    }
    return 0;
}

